package com.example.redissondemo.utils;

import io.micrometer.common.util.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.*;
import org.redisson.api.geo.GeoSearchArgs;
import org.redisson.api.listener.MessageListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;

import java.time.Duration;
import java.util.*;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author Liunh
 */
@Slf4j
@Component
public class RedissonUtil {

    private final RedissonClient redissonClient;
    public static final String REDIS_PRE_LOCK_KEY = "REDISSON_LOCK_KEY_";
    public static final String REDIS_PRE_TOPIC_KEY = "REDISSON_TOPIC_KEY_";


    @Autowired
    private RedissonUtil(RedissonClient redissonClient) {
        this.redissonClient = redissonClient;
    }

    /**
     * 查询所有的 keys
     *
     * @return
     */
    @GetMapping("/all")
    public String keys() {
        return redissonClient.getKeys().toString();
    }

// ------------------------------------------ IdGenerator ---------------------------------------------------------

    public long getId(String key) {
        if (StringUtils.isNotBlank(key)) {
            return redissonClient.getIdGenerator(key).nextId();
        }
        return -1;
    }

// ------------------------------------------ Bucket String -------------------------------------------------------

    /**
     * 字符串存储
     *
     * @param key
     */
    public void getRBucket(String key) {
        if (StringUtils.isNotBlank(key)) {
            redissonClient.getBucket(key);
        }
    }

    public void set(String key, String val) {
        if (StringUtils.isNotBlank(key)) {
            redissonClient.getBucket(key).set(val);
        }
    }

    public void set(String key, String val, Duration duration) {
        if (StringUtils.isNotBlank(key)) {
            redissonClient.getBucket(key).set(val, duration);
        }
    }

    public Object getAndSet(String key, String val) {
        if (StringUtils.isNotBlank(key)) {
            return redissonClient.getBucket(key).getAndSet(val);
        }
        return null;
    }

    public void setIfExists(String key, String val) {
        if (StringUtils.isNotBlank(key)) {
            redissonClient.getBucket(key).setIfExists(val);
        }
    }

    public Object get(String key) {
        if (StringUtils.isNotBlank(key)) {
            return redissonClient.getBucket(key).get();
        }
        return null;
    }

// ------------------------------------------ Buckets Map ---------------------------------------------------------

    /**
     * 字符串存储
     *
     * @param val
     */
    public void mPut(Map val) {
        if (val != null) {
            redissonClient.getBuckets().set(val);
        }
    }

    public Map mPet(String key) {
        if (StringUtils.isNotBlank(key)) {
            return redissonClient.getBuckets().get(key);
        }
        return null;
    }

// ------------------------------------------ Map ---------------------------------------------------------

    /**
     * Map存储
     *
     * @param key
     */
    public RMap getRMap(String key) {
        if (StringUtils.isNotBlank(key)) {
            return redissonClient.getMap(key);
        }
        return null;
    }

    public void mPut(String key, Map val) {
        if (StringUtils.isNotBlank(key) && val != null && val.size() > 0) {
            RMap<Object, Object> keyObj = redissonClient.getMap(key);
            val.forEach((k, v) -> keyObj.put(k, v));
        }
    }

    public Object mAddAndGet(String key, AtomicInteger index) {
        if (StringUtils.isNotBlank(key)) {
            return redissonClient.getMap(key).addAndGet(key, index);
        }
        return null;
    }

    public Object mGet(String key, String mapKey) {
        if (StringUtils.isNotBlank(key) && StringUtils.isNotBlank(mapKey)) {
            return redissonClient.getMap(key).get(mapKey);
        }
        return null;
    }

    public boolean mContainsKey(String key, String mapKey) {
        if (StringUtils.isNotBlank(key) && StringUtils.isNotBlank(mapKey)) {
            return redissonClient.getMap(key).containsKey(mapKey);
        }
        return false;
    }

    public boolean mContainsValue(String key, Object val) {
        if (StringUtils.isNotBlank(key)) {
            return redissonClient.getMap(key).containsValue(val);
        }
        return false;
    }

    public Object mRemove(String key, String mapKey) {
        if (StringUtils.isNotBlank(key) && StringUtils.isNotBlank(mapKey)) {
            return redissonClient.getMap(key).remove(mapKey);
        }
        return null;
    }

    public Object mReplace(String key, String mapKey, Object replace) {
        if (StringUtils.isNotBlank(key) && StringUtils.isNotBlank(mapKey)) {
            return redissonClient.getMap(key).replace(mapKey, replace);
        }
        return null;
    }

    public void mPutAll(String key, Map map) {
        if (StringUtils.isNotBlank(key)) {
            redissonClient.getMap(key).putAll(map);
        }
    }

// ------------------------------------------ Set ---------------------------------------------------------

    /**
     * Set存储
     *
     * @param key
     * @return
     */
    public RSet getRSet(String key) {
        if (StringUtils.isNotBlank(key)) {
            return redissonClient.getSet(key);
        }
        return null;
    }

    public void sAdd(String key, Set val) {
        if (StringUtils.isNotBlank(key)) {
            RSet keyObj = redissonClient.getSet(key);
            val.forEach(v -> keyObj.add(v));
        }
    }

    public boolean sAddAll(String key, Collection obj) {
        if (key != null) {
            return redissonClient.getSet(key).addAll(obj);
        }
        return false;
    }

    public Iterator sIterator(String key) {
        if (key != null) {
            return redissonClient.getSet(key).iterator();
        }
        return null;
    }

    public Set sGet(String key) {
        Set set = null;
        if (key != null) {
            set = new HashSet();
            RSet rSet = redissonClient.getSet(key);
            int size = rSet.size();
            Iterator iterator = rSet.iterator();
            while (iterator.hasNext()) {
                set.add(iterator.next());
            }
        }
        return set;
    }

    public boolean sContains(String key, Object obj) {
        if (key != null) {
            return redissonClient.getSet(key).contains(obj);
        }
        return false;
    }

    public boolean sContainsAll(String key, Collection obj) {
        if (key != null) {
            return redissonClient.getSet(key).containsAll(obj);
        }
        return false;
    }

    public int sSize(String key, int index) {
        if (key != null) {
            return redissonClient.getSet(key).size();
        }
        return 0;
    }

    public boolean sRemove(String key, int index) {
        if (key != null) {
            return redissonClient.getSet(key).remove(index);
        }
        return false;
    }

    public boolean sRemoveAll(String key, Collection obj) {
        if (StringUtils.isNotBlank(key)) {
            return redissonClient.getSet(key).removeAll(obj);
        }
        return false;
    }

    public void sClear(String key, Object obj) {
        if (StringUtils.isNotBlank(key)) {
            redissonClient.getSet(key).clear();
        }
    }

// ------------------------------------------ List ---------------------------------------------------------

    /**
     * List存储
     *
     * @param key
     * @return
     */
    public RList getRList(String key) {
        if (StringUtils.isNotBlank(key)) {
            return redissonClient.getList(key);
        }
        return null;
    }

    public boolean lAdd(String key, List val) {
        if (StringUtils.isNotBlank(key) && val != null && val.size() > 0) {
            RList keyObj = redissonClient.getList(key);
            val.forEach(v -> keyObj.add(v));
            return true;
        }
        return false;
    }

    public boolean lAddAll(String key, Collection val) {
        if (StringUtils.isNotBlank(key) && val != null && val.size() > 0) {
            return redissonClient.getList(key).addAll(val);
        }
        return false;
    }

    public void lSet(String key, int index, Object val) {
        if (StringUtils.isNotBlank(key) && val != null) {
            redissonClient.getList(key).set(index, val);
        }
    }

    public List lSubList(String key, int fromIndex, int toIndex) {
        if (StringUtils.isNotBlank(key)) {
            return redissonClient.getList(key).subList(fromIndex, toIndex);
        }
        return null;
    }

    public Object lGet(String key, int index) {
        if (StringUtils.isNotBlank(key)) {
            return redissonClient.getList(key).get(index);
        }
        return null;
    }

    public List lGet(String key) {
        List list = null;
        if (StringUtils.isNotBlank(key)) {
            list = new ArrayList();
            int size = redissonClient.getList(key).size();
            for (int i = 0; i < size; i++) {
                list.add(redissonClient.getList(key).get(i));
            }
        }
        return list;
    }

    public Object lRemoveByIndex(String key, int index) {
        if (StringUtils.isNotBlank(key)) {
            return redissonClient.getList(key).remove(index);
        }
        return null;
    }

    public Object lRemoveByObj(String key, Object obj) {
        if (StringUtils.isNotBlank(key)) {
            return redissonClient.getList(key).remove(obj);
        }
        return null;
    }

    public boolean lRemoveAll(String key, Collection obj) {
        if (StringUtils.isNotBlank(key)) {
            return redissonClient.getList(key).removeAll(obj);
        }
        return false;
    }

    public void lClear(String key, Object obj) {
        if (StringUtils.isNotBlank(key)) {
            redissonClient.getList(key).clear();
        }
    }

    public boolean lContains(String key, Object obj) {
        if (StringUtils.isNotBlank(key)) {
            return redissonClient.getList(key).contains(obj);
        }
        return false;
    }

    public boolean lContainsAll(String key, Collection obj) {
        if (StringUtils.isNotBlank(key)) {
            return redissonClient.getList(key).containsAll(obj);
        }
        return false;
    }

    public int lSize(String key) {
        if (StringUtils.isNotBlank(key)) {
            return redissonClient.getList(key).size();
        }
        return 0;
    }

    public boolean lIsEmpty(String key) {
        if (StringUtils.isNotBlank(key)) {
            return redissonClient.getList(key).isEmpty();
        }
        return true;
    }

// ------------------------------------------ BitSet ---------------------------------------------------------

    public RBitSet getRBitSet(String key) {
        if (StringUtils.isNotBlank(key)) {
            return redissonClient.getBitSet(key);
        }
        return null;
    }

    public Object bSet(String key, long index, boolean val) {
        if (StringUtils.isNotBlank(key)) {
            return redissonClient.getBitSet(key).set(index, val);
        }
        return null;
    }

    public boolean bGet(String key, int index) {
        if (StringUtils.isNotBlank(key)) {
            return redissonClient.getBitSet(key).get(index);
        }
        return false;
    }

// ------------------------------------------ SortedSet ---------------------------------------------------------

    public RSortedSet getRSortedSet(String key) {
        if (StringUtils.isNotBlank(key)) {
            return redissonClient.getSortedSet(key);
        }
        return null;
    }

    public boolean ssAdd(String key, Object val) {
        if (StringUtils.isNotBlank(key)) {
            return redissonClient.getSortedSet(key).add(val);
        }
        return false;
    }

    public boolean ssAddAll(String key, Collection val) {
        if (StringUtils.isNotBlank(key)) {
            return redissonClient.getSortedSet(key).addAll(val);
        }
        return false;
    }

    public boolean ssRemove(String key, Object val) {
        if (StringUtils.isNotBlank(key)) {
            return redissonClient.getSortedSet(key).remove(val);
        }
        return false;
    }

    public boolean ssRemoveAll(String key, Collection val) {
        if (StringUtils.isNotBlank(key)) {
            return redissonClient.getSortedSet(key).removeAll(val);
        }
        return false;
    }

    public Collection ssReadAll(String key) {
        if (StringUtils.isNotBlank(key)) {
            return redissonClient.getSortedSet(key).readAll();
        }
        return null;
    }

// ------------------------------------------ Geo ---------------------------------------------------------

    public RGeo getRGeo(String key) {
        if (StringUtils.isNotBlank(key)) {
            return redissonClient.getGeo(key);
        }
        return null;
    }

    public Object gSet(String key, double score, Object val) {
        if (StringUtils.isNotBlank(key)) {
            return redissonClient.getGeo(key).add(score, val);
        }
        return null;
    }

    public List gSearch(String key, GeoSearchArgs args) {
        if (StringUtils.isNotBlank(key)) {
            return redissonClient.getGeo(key).search(args);
        }
        return null;
    }

// ------------------------------------------ HyperLogLog ---------------------------------------------------------

    public RHyperLogLog getHyperLogLog(String queueName) {
        if (StringUtils.isNotBlank(queueName)) {
            return redissonClient.getHyperLogLog(queueName);
        }
        return null;
    }

    public boolean logAdd(String queueName, Object val) {
        if (StringUtils.isNotBlank(queueName)) {
            return redissonClient.getHyperLogLog(queueName).add(val);
        }
        return false;
    }

    public boolean logAddAll(String queueName, Collection vals) {
        if (StringUtils.isNotBlank(queueName)) {
            return redissonClient.getHyperLogLog(queueName).addAll(vals);
        }
        return false;
    }

    public long logCount(String queueName) {
        if (StringUtils.isNotBlank(queueName)) {
            return redissonClient.getHyperLogLog(queueName).count();
        }
        return 0;
    }

    public long logCount(String queueName, String... otherLogNames) {
        if (StringUtils.isNotBlank(queueName)) {
            return redissonClient.getHyperLogLog(queueName).countWith(otherLogNames);
        }
        return 0;
    }

    public void logMerge(String queueName, String... otherLogNames) {
        if (StringUtils.isNotBlank(queueName)) {
            redissonClient.getHyperLogLog(queueName).mergeWith(otherLogNames);
        }
    }

// ------------------------------------------ Queue ---------------------------------------------------------

    public RQueue getRQueue(String queueName) {
        if (StringUtils.isNotBlank(queueName)) {
            return redissonClient.getQueue(queueName);
        }
        return null;
    }

    public boolean qSet(String queueName, Object val) {
        if (StringUtils.isNotBlank(queueName)) {
            return redissonClient.getQueue(queueName).add(val);
        }
        return false;
    }

    public Object qPoll(String queueName) {
        if (StringUtils.isNotBlank(queueName)) {
            return redissonClient.getQueue(queueName).poll();
        }
        return null;
    }

    public Object qRemove(String queueName) {
        if (StringUtils.isNotBlank(queueName)) {
            return redissonClient.getQueue(queueName).remove();
        }
        return null;
    }

// ------------------------------------------ TransferQueue ---------------------------------------------------------

    public RTransferQueue getRTransferQueue(String queueName) {
        if (StringUtils.isNotBlank(queueName)) {
            return redissonClient.getTransferQueue(queueName);
        }
        return null;
    }

    public boolean tqSet(String queueName, Object val) {
        if (StringUtils.isNotBlank(queueName)) {
            return redissonClient.getTransferQueue(queueName).add(val);
        }
        return false;
    }

    public Object tqReadAll(String queueName) {
        if (StringUtils.isNotBlank(queueName)) {
            return redissonClient.getTransferQueue(queueName).readAll();
        }
        return null;
    }

// ------------------------------------------ DelayedQueue  ---------------------------------------------------------

    public RDelayedQueue getRDelayedQueue(String queueName) {
        if (StringUtils.isNotBlank(queueName)) {
            return redissonClient.getDelayedQueue(redissonClient.getQueue(queueName));
        }
        return null;
    }

    public boolean dqSet(String queueName, Object val) {
        if (StringUtils.isNotBlank(queueName)) {
            return redissonClient.getDelayedQueue(redissonClient.getQueue(queueName)).add(val);
        }
        return false;
    }

    public Object dqPoll(String queueName) {
        if (StringUtils.isNotBlank(queueName)) {
            return redissonClient.getDelayedQueue(redissonClient.getQueue(queueName)).poll();
        }
        return null;
    }

// ------------------------------------------ RingBuffer ---------------------------------------------------------

    public RRingBuffer getRingBuffer(String queueName) {
        if (StringUtils.isNotBlank(queueName)) {
            return redissonClient.getRingBuffer(queueName);
        }
        return null;
    }

    public boolean rSet(String queueName, Object val) {
        if (StringUtils.isNotBlank(queueName)) {
            return redissonClient.getRingBuffer(queueName).add(val);
        }
        return false;
    }

    public void rSet(String queueName, int capacity) {
        if (StringUtils.isNotBlank(queueName)) {
            redissonClient.getRingBuffer(queueName).setCapacity(capacity);
        }
    }

    public int rRemainingCapacity(String queueName) {
        if (StringUtils.isNotBlank(queueName)) {
            return redissonClient.getRingBuffer(queueName).remainingCapacity();
        }
        return 0;
    }

    public int rCapacity(String queueName) {
        if (StringUtils.isNotBlank(queueName)) {
            return redissonClient.getRingBuffer(queueName).capacity();
        }
        return 0;
    }

    public Object rRemove(String queueName) {
        if (StringUtils.isNotBlank(queueName)) {
            return redissonClient.getRingBuffer(queueName).remove();
        }
        return null;
    }

    public Object rPoll(String queueName) {
        if (StringUtils.isNotBlank(queueName)) {
            return redissonClient.getRingBuffer(queueName).poll();
        }
        return null;
    }

// ------------------------------------------ BlockingQueue ---------------------------------------------------------

    public BlockingQueue bAPoll(String queueName) {
        if (StringUtils.isNotBlank(queueName)) {
            return redissonClient.getBlockingQueue(queueName);
        }
        return null;
    }

    public boolean bAdd(String queueName, Object val) {
        if (StringUtils.isNotBlank(queueName)) {
            return redissonClient.getBlockingQueue(queueName).add(val);
        }
        return false;
    }

    public Object bPoll(String queueName) {
        if (StringUtils.isNotBlank(queueName)) {
            return redissonClient.getBlockingQueue(queueName).poll();
        }
        return null;
    }

    public Object bRemove(String queueName) {
        if (StringUtils.isNotBlank(queueName)) {
            return redissonClient.getBlockingQueue(queueName).remove();
        }
        return null;
    }

// ------------------------------------------ RateLimiter ---------------------------------------------------------

    public RRateLimiter getRRateLimiter(String key) {
        if (StringUtils.isNotBlank(key)) {
            return redissonClient.getRateLimiter(key);
        }
        return null;
    }

    public void tryAcquire(String key, long permits) {
        if (StringUtils.isNotBlank(key)) {
            redissonClient.getRateLimiter(key).tryAcquire(permits);
        }
    }

    public void acquire(String key, long permits) {
        if (StringUtils.isNotBlank(key)) {
            redissonClient.getRateLimiter(key).acquire(permits);
        }
    }

    public void setRate(String key, RateType mode, long rate, long rateInterval, RateIntervalUnit rateIntervalUnit) {
        if (StringUtils.isNotBlank(key)) {
            redissonClient.getRateLimiter(key).setRate(mode, rate, rateInterval, rateIntervalUnit);
        }
    }

// ------------------------------------------ CountDownLatch ---------------------------------------------------------

    public RCountDownLatch getRCountDownLatch(String key) {
        if (StringUtils.isNotBlank(key)) {
            redissonClient.getCountDownLatch(key);
        }
        return null;
    }

    public boolean trySetCount(String key, long count) {
        if (StringUtils.isNotBlank(key)) {
            return redissonClient.getCountDownLatch(key).trySetCount(count);
        }
        return false;
    }

    public void await(String key) throws InterruptedException {
        if (StringUtils.isNotBlank(key)) {
            redissonClient.getCountDownLatch(key).await();
        }
    }

    public boolean await(String key, long timeout, TimeUnit unit) throws InterruptedException {
        if (StringUtils.isNotBlank(key)) {
            return redissonClient.getCountDownLatch(key).await(timeout, unit);
        }
        return false;
    }

    public void countDown(String key) {
        if (StringUtils.isNotBlank(key)) {
            redissonClient.getCountDownLatch(key).countDown();
        }
    }

// ------------------------------------------ RLongAdder ---------------------------------------------------------

    public RLongAdder getRLongAdder(String key) {
        if (StringUtils.isNotBlank(key)) {
            redissonClient.getLongAdder(key);
        }
        return null;
    }

    public void addLong(String key, long newValue) {
        if (StringUtils.isNotBlank(key)) {
            redissonClient.getLongAdder(key).add(newValue);
        }
    }

    public void incrementLong(String key) {
        if (StringUtils.isNotBlank(key)) {
            redissonClient.getLongAdder(key).increment();
        }
    }

    public void decrementLong(String key) {
        if (StringUtils.isNotBlank(key)) {
            redissonClient.getLongAdder(key).decrement();
        }
    }

    public long sumLong(String key) {
        if (StringUtils.isNotBlank(key)) {
            return redissonClient.getLongAdder(key).sum();
        }
        return 0L;
    }

    public void resetLong(String key) {
        redissonClient.getLongAdder(key).reset();
    }

// ------------------------------------------ RDoubleAdder ---------------------------------------------------------

    public RDoubleAdder getRDoubleAdder(String key) {
        if (StringUtils.isNotBlank(key)) {
            redissonClient.getDoubleAdder(key);
        }
        return null;
    }

    public void addDouble(String key, double newValue) {
        if (StringUtils.isNotBlank(key)) {
            redissonClient.getDoubleAdder(key).add(newValue);
        }
    }

    public void incrementDouble(String key) {
        if (StringUtils.isNotBlank(key)) {
            redissonClient.getDoubleAdder(key).increment();
        }
    }

    public void decrementDouble(String key) {
        if (StringUtils.isNotBlank(key)) {
            redissonClient.getDoubleAdder(key).decrement();
        }
    }

    public double sumDouble(String key) {
        if (StringUtils.isNotBlank(key)) {
            return redissonClient.getDoubleAdder(key).sum();
        }
        return 0d;
    }

    public void resetDouble(String key) {
        if (StringUtils.isNotBlank(key)) {
            redissonClient.getDoubleAdder(key).reset();
        }
    }

// ------------------------------------------ AtomicLong ---------------------------------------------------------

    public RAtomicLong getRAtomicLong(String key) {
        if (StringUtils.isNotBlank(key)) {
            redissonClient.getAtomicLong(key);
        }
        return null;
    }

    public void setLong(String key, long newValue) {
        if (StringUtils.isNotBlank(key)) {
            redissonClient.getAtomicLong(key).set(newValue);
        }
    }

    public long getAndAddLong(String key, long delta) {
        if (StringUtils.isNotBlank(key)) {
            return redissonClient.getAtomicLong(key).getAndAdd(delta);
        }
        return 0L;
    }

    public long getAndSetLong(String key, long newValue) {
        if (StringUtils.isNotBlank(key)) {
            return redissonClient.getAtomicLong(key).getAndSet(newValue);
        }
        return 0L;
    }

    public long getAndDeleteLong(String key) {
        if (StringUtils.isNotBlank(key)) {
            return redissonClient.getAtomicLong(key).getAndDelete();
        }
        return 0L;
    }

    public long getLong(String key) {
        if (StringUtils.isNotBlank(key)) {
            return redissonClient.getAtomicLong(key).get();
        }
        return 0L;
    }

    public long incrementAndGetAtomicLong(String key) {
        if (StringUtils.isNotBlank(key)) {
            return redissonClient.getAtomicLong(key).incrementAndGet();
        }
        return 0L;
    }

    public long decrementAndGetLong(String key) {
        if (StringUtils.isNotBlank(key)) {
            return redissonClient.getAtomicLong(key).decrementAndGet();
        }
        return 0L;
    }

    public long getAndDecrementLong(String key) {
        if (StringUtils.isNotBlank(key)) {
            return redissonClient.getAtomicLong(key).getAndDecrement();
        }
        return 0L;
    }

// ------------------------------------------ AtomicDouble ---------------------------------------------------------

    public RAtomicDouble getRAtomicDouble(String key) {
        if (StringUtils.isNotBlank(key)) {
            redissonClient.getAtomicDouble(key);
        }
        return null;
    }

    public void setDouble(String key, double newValue) {
        if (StringUtils.isNotBlank(key)) {
            redissonClient.getAtomicDouble(key).set(newValue);
        }
    }

    public double getDouble(String key) {
        if (StringUtils.isNotBlank(key)) {
            return redissonClient.getAtomicDouble(key).get();
        }
        return 0d;
    }

    public double getAndAddDouble(String key, double delta) {
        if (StringUtils.isNotBlank(key)) {
            return redissonClient.getAtomicDouble(key).getAndAdd(delta);
        }
        return 0d;
    }

    public double getAndSetDouble(String key, double newValue) {
        if (StringUtils.isNotBlank(key)) {
            return redissonClient.getAtomicDouble(key).getAndSet(newValue);
        }
        return 0d;
    }

    public double getAndDeleteDouble(String key) {
        if (StringUtils.isNotBlank(key)) {
            return redissonClient.getAtomicDouble(key).getAndDelete();
        }
        return 0d;
    }

    public double incrementAndGetDouble(String key) {
        if (StringUtils.isNotBlank(key)) {
            return redissonClient.getAtomicDouble(key).incrementAndGet();
        }
        return 0d;
    }

    public double decrementAndGetDouble(String key) {
        if (StringUtils.isNotBlank(key)) {
            return redissonClient.getAtomicDouble(key).decrementAndGet();
        }
        return 0d;
    }

    public double getAndDecrementDouble(String key) {
        if (StringUtils.isNotBlank(key)) {
            return redissonClient.getAtomicDouble(key).getAndDecrement();
        }
        return 0d;
    }

// ------------------------------------------ RLock ---------------------------------------------------------

    public RTopic getRTopic(String channelName) {
        if (StringUtils.isNotBlank(channelName)) {
            return redissonClient.getTopic(channelName);
        }
        return null;
    }

    /**
     * RTopic发送消息
     * 需要注意的是，发布消息与监听消息要运行在不同的 JVM，
     * 如果使用同一个 redissonClient 发布的话，不会监听到自己的消息。
     *
     * @param channelName
     * @param type
     * @param listener
     * @param message
     * @return
     */
    public <M> long sendMsg(String channelName, Class<M> type, MessageListener<? extends M> listener, Object message) {
        long publishCount = 0L;
        if (channelName != null) {
            RTopic topic = redissonClient.getTopic(channelName);
            if (topic.countListeners() < 1) {
                topic.addListener(type, listener);
            }
            publishCount = topic.publish(message);
            if (message instanceof String) {
                log.info(">>>>>> RTopic生产者发送消息成功，msg = {}", message);
            } else {
                log.info(">>>>>> RTopic生产者发送消息成功，msg = {}", JacksonUtil.beanToJson(message));
            }
            //redissonClient.shutdown();
        }
        return publishCount;
    }


// ------------------------------------------ RLock ---------------------------------------------------------

    /**
     * lock(), 拿不到lock就不罢休，不然线程就一直block
     *
     * @param lockKey
     * @return
     */
    public RLock lock(String lockKey) {
        if (StringUtils.isNotBlank(lockKey)) {
            final RLock lock = redissonClient.getLock(lockKey);
            lock.lock();
            return lock;
        }
        return null;
    }

    /**
     * leaseTime为加锁时间，单位为秒
     *
     * @param lockKey
     * @param leaseTime
     * @return
     */
    public RLock lock(String lockKey, long leaseTime) {
        if (StringUtils.isNotBlank(lockKey)) {
            final RLock lock = redissonClient.getLock(lockKey);
            lock.lock(leaseTime, TimeUnit.SECONDS);
            return lock;
        }
        return null;
    }

    /**
     * timeout为加锁时间，时间单位由unit确定
     *
     * @param lockKey
     * @param unit
     * @param timeout
     * @return
     */
    public RLock lock(String lockKey, TimeUnit unit, long timeout) {
        if (StringUtils.isNotBlank(lockKey)) {
            final RLock lock = redissonClient.getLock(lockKey);
            lock.lock(timeout, unit);
            return lock;
        }
        return null;
    }

    public boolean tryLock(String lockKey, TimeUnit unit, long waitTime, long leaseTime) {
        if (StringUtils.isNotBlank(lockKey)) {
            try {
                return redissonClient.getLock(lockKey).tryLock(waitTime, leaseTime, unit);
            } catch (InterruptedException e) {
                return false;
            }
        }
        return false;
    }

    public void unlock(String lockKey) {
        redissonClient.getLock(lockKey).unlock();
    }

    public void unlock(RLock lock) {
        if (lock != null && lock.isLocked() && lock.isHeldByCurrentThread()) {
            lock.unlock();
        }
    }

// ----------------------------------------------------------------------------------------------------------------

    public void shutdown() {
        redissonClient.shutdown();
    }

}
